home *** CD-ROM | disk | FTP | other *** search
/ Suzy B Software 2 / Suzy B Software CD-ROM 2 (1994).iso / new_file / mintprgs / mint112s / mint112s.lzh / main.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-15  |  40.5 KB  |  1,563 lines

  1. /*
  2. Copyright 1990,1991,1992 Eric R. Smith.
  3. Copyright 1992,1993,1994 Atari Corporation.
  4. All rights reserved.
  5. */
  6.  
  7. #include "mint.h"
  8. #include "version.h"
  9. #include "cookie.h"
  10. #include "xbra.h"
  11.  
  12. /* the kernel's stack size */
  13. #define STACK    8*1024L
  14.  
  15. /* if the user is holding down the magic shift key, we ask before booting */
  16. #define MAGIC_SHIFT 0x2        /* left shift */
  17.  
  18. /* magic number to show that we have captured the reset vector */
  19. #define RES_MAGIC 0x31415926L
  20.  
  21. static void xbra_install P_((xbra_vec *, long, long ARGS_ON_STACK (*)()));
  22. static void init_intr P_((void));
  23. static long getmch P_((void));
  24. static void do_line P_((char *));
  25. static void do_file P_((int));
  26. static void shutmedown P_((PROC *));
  27. void shutdown P_((void));
  28. static void doset P_((char *,char *));
  29. static long ARGS_ON_STACK mint_criticerr P_((long));
  30. static void ARGS_ON_STACK do_exec_os P_((register long basepage));
  31.  
  32. static int gem_active;    /* 0 if AES has not started, nonzero otherwise */
  33.  
  34. #define EXEC_OS 0x4feL
  35. static int  check_for_gem P_((void));
  36. static void run_auto_prgs P_((void));
  37.  
  38. #ifdef LATTICE
  39. /*
  40.  * AGK: this is witchcraft to completely replace the startup code for
  41.  * Lattice; doing so saves around 10K on the final binary and pulls only
  42.  * long division & multitplication from the library (and not even those
  43.  * if you compile for native '030). The drawback of this code is it
  44.  * passes no environment or command line whatsoever. Since I always
  45.  * set MiNT options & environment in 'mint.cnf' this is not a personal
  46.  * downer, however at some point in the future we ought to have a kernel
  47.  * parseargs() like call which sets these things up.
  48.  */ 
  49. BASEPAGE *_base;
  50.  
  51. static void
  52. start(BASEPAGE *bp)
  53. {
  54.     long shrinklen;
  55.     
  56.     _base = bp;
  57.     shrinklen = bp->p_tlen + bp->p_dlen + bp->p_blen + STACK + 0x100;
  58.     if (bp->p_lowtpa + shrinklen <= bp->p_hitpa) {
  59.         static char null[1] = {""};
  60.         static char *argv[2] = {null, NULL};
  61.         extern __builtin_putreg P_((int, long));    /* totally bogus */
  62.  
  63.         __builtin_putreg(15, bp->p_lowtpa + shrinklen);
  64.         Mshrink((void *)bp->p_lowtpa, shrinklen);
  65.         main(1, argv);
  66.     }
  67.     Pterm(ENSMEM);
  68. }
  69. #endif
  70.  
  71. #if defined(__GNUC__) || defined(__MINT__)
  72. long _stksize = STACK;
  73. #ifndef PROFILING
  74. #include <minimal.h>
  75. #endif
  76. #endif
  77.  
  78. int curs_off = 0;    /* set if we should turn the cursor off when exiting */
  79. int mint_errno = 0;    /* error return from open and creat filesystem calls */
  80.  
  81. /*
  82.  * AGK: for proper co-processors we must consider saving their context.
  83.  * This variable when non-zero indicates that the BIOS considers a true
  84.  * coprocessor to be present. We use this variable in the context switch
  85.  * code to decide whether to attempt an FPU context save.
  86.  */
  87. short fpu = 0;
  88.  
  89. /*
  90.  * "mch" holds what kind of machine we are running on
  91.  */
  92. long mch = 0;
  93.  
  94. /*
  95.  * "screen_boundary+1" tells us how screens must be positioned
  96.  * (to a 256 byte boundary on STs, a 16 byte boundary on other
  97.  * machines; actually, 16 bytes is conservative, 4 is probably
  98.  * OK, but it doesn't hurt to be cautious). The +1 is because
  99.  * we're using this as a mask in the ROUND() macro in mem.h.
  100.  */
  101. int screen_boundary = 255;
  102.  
  103. /*
  104.  * variable holds processor type
  105.  */
  106. long mcpu = 0;
  107.  
  108. /*
  109.  * variable holds language preference
  110.  */
  111. int gl_lang = -1;
  112.  
  113. /*
  114.  * variable set if someone has already installed an flk cookie
  115.  */
  116. int flk = 0;
  117.  
  118. /*
  119.  * variable set to 1 if the _VDO cookie indicates Falcon style video
  120.  */
  121. int FalconVideo;
  122.  
  123. /* program to run at startup */
  124. #ifdef MULTITOS
  125. static int init_is_gem = 1;    /* set to 1 if init_prg is GEM */
  126. #else
  127. static int init_is_gem = 0;    /* set to 1 if init_prg is GEM */
  128. BASEPAGE *gem_base = 0;
  129. long gem_start = 0;
  130. #endif
  131. static const char *init_prg = 0;
  132.  
  133. /* note: init_tail is also used as a temporary stack for resets in
  134.  * intr.spp
  135.  */
  136. char init_tail[256];
  137.  
  138. /* initial environment for that program */
  139. static char *init_env = 0;
  140. /* temporary pointer into that environment for setenv */
  141. static char *env_ptr;
  142. /* length of the environment */
  143. static long env_len;
  144.  
  145. /* GEMDOS pointer to current basepage */
  146. BASEPAGE **tosbp;
  147.  
  148. /* pointer to the BIOS keyboard shift variable */
  149. extern char *kbshft;    /* see bios.c */
  150. extern BCONMAP2_T *bconmap2;    /* bconmap struct, see bios.c */
  151.  
  152. /* version of TOS we're running over */
  153. int tosvers;
  154.  
  155. /* structures for keyboard/MIDI interrupt vectors */
  156. KBDVEC *syskey, oldkey;
  157. xbra_vec old_ikbd;            /* old ikbd vector */
  158.  
  159. /* values the user sees for the DOS, BIOS, and XBIOS vectors */
  160. long save_dos, save_bios, save_xbios;
  161.  
  162. /* values for original system vectors */
  163. xbra_vec old_dos, old_bios, old_xbios, old_timer, old_vbl, old_5ms;
  164. xbra_vec old_criticerr;
  165. xbra_vec old_execos;
  166.  
  167. long old_term;
  168.  
  169. xbra_vec old_resvec;    /* old reset vector */
  170. long old_resval;    /* old reset validation */
  171.  
  172. #ifdef EXCEPTION_SIGS
  173. /* bus error, address error, illegal instruction, etc. vectors */
  174. xbra_vec old_bus, old_addr, old_ill, old_divzero, old_trace, old_priv;
  175. xbra_vec old_linef, old_chk, old_trapv, old_mmuconf, old_format, old_cpv;
  176. xbra_vec old_uninit, old_spurious, old_fpcp[7], old_pmmuill, old_pmmuacc;
  177. #endif
  178.  
  179. /* BIOS disk vectors */
  180. xbra_vec old_mediach, old_getbpb, old_rwabs;
  181.  
  182. /* BIOS drive map */
  183. long olddrvs;
  184.  
  185. extern Func bios_tab[], dos_tab[];
  186.  
  187. /* kernel info that is passed to loaded file systems and device drivers */
  188.  
  189. struct kerinfo kernelinfo = {
  190.     MAJ_VERSION, MIN_VERSION,
  191.     DEFAULT_MODE, 0,
  192.     bios_tab, dos_tab,
  193.     changedrv,
  194.     Trace, Debug, ALERT, FATAL,
  195.     kmalloc, kfree, umalloc, ufree,
  196.     strnicmp, stricmp, strlwr, strupr, ksprintf,
  197.     ms_time, unixtim, dostim,
  198.     nap, sleep, wake, wakeselect,
  199.     denyshare, denylock, addtimeout, canceltimeout,
  200.     addroottimeout, cancelroottimeout,
  201.     ikill,iwake
  202. };
  203.  
  204. /* table of processor frame sizes in _words_ (not used on MC68000) */
  205. unsigned char framesizes[16] = {
  206. /*0*/    0,    /* MC68010/M68020/M68030/M68040 short */
  207. /*1*/    0,    /* M68020/M68030/M68040 throwaway */
  208. /*2*/    2,    /* M68020/M68030/M68040 instruction error */
  209. /*3*/    2,    /* M68040 floating point post instruction */
  210. /*4*/    3,    /* MC68LC040/MC68EC040 unimplemented floating point instruction */
  211. /*5*/    0,    /* NOTUSED */
  212. /*6*/    0,    /* NOTUSED */
  213. /*7*/    26,    /* M68040 access error */    
  214. /*8*/    25,    /* MC68010 long */    
  215. /*9*/    6,    /* M68020/M68030 mid instruction */
  216. /*A*/    12,    /* M68020/M68030 short bus cycle */
  217. /*B*/    42,    /* M68020/M68030 long bus cycle */
  218. /*C*/    8,    /* CPU32 bus error */
  219. /*D*/    0,    /* NOTUSED */
  220. /*E*/    0,    /* NOTUSED */
  221. /*F*/    13    /* 68070 and 9xC1xx microcontroller address error */
  222. };
  223.  
  224. /* TOS and MiNT cookie jars, respectively. See the comments and code 
  225.  * after main() for further details
  226.  */
  227.  
  228. COOKIE *oldcookie, *newcookie;
  229.  
  230. /*
  231.  * install a new vector for address "addr", using the XBRA protocol.
  232.  * must run in supervisor mode!
  233.  */
  234.  
  235. static void
  236. xbra_install(xv, addr, func)
  237.     xbra_vec *xv;
  238.     long addr;
  239.     long ARGS_ON_STACK (*func)();
  240. {
  241.     xv->xbra_magic = XBRA_MAGIC;
  242.     xv->xbra_id = MINT_MAGIC;
  243.     xv->jump = JMP_OPCODE;
  244.     xv->this = func;
  245.     xv->next = *((struct xbra **)addr);
  246.     *((short **)addr) = &xv->jump;
  247. }
  248.  
  249. /*
  250.  * MiNT critical error handler; all it does is to jump through
  251.  * the vector for the current process
  252.  */
  253.  
  254. static long ARGS_ON_STACK
  255. mint_criticerr(error)
  256.     long error;    /* high word is error, low is drive */
  257. {
  258.     return (*curproc->criticerr)(error);
  259. }
  260.  
  261. /*
  262.  * if we are MultiTOS, and if we are running from the AUTO folder,
  263.  * then we grab the exec_os vector and use that to start GEM; that
  264.  * way programs that expect exec_os to act a certain way will still
  265.  * work.
  266.  * NOTE: we must use Pexec instead of p_exec here, because we will
  267.  * be running in a user context (that of process 1, not process 0)
  268.  */
  269.  
  270. static void ARGS_ON_STACK
  271. do_exec_os(basepage)
  272.     register long basepage;
  273. {
  274.     register long r;
  275.  
  276. /* if the user didn't specify a startup program, jump to the ROM */
  277.     if (!init_prg) {
  278.         register void ARGS_ON_STACK (*f) P_((long));
  279.         f = (void ARGS_ON_STACK (*) P_((long))) old_execos.next;
  280.         (*f)(basepage);
  281.         Pterm0();
  282.     } else {        
  283.  
  284. /* we have to set a7 to point to lower in our TPA; otherwise we would
  285.  * bus error right after the Mshrink call!
  286.  */
  287.         setstack(basepage+500L);
  288. #if defined(__TURBOC__) && !defined(__MINT__)
  289.         Mshrink(0, (void *)basepage, 512L);
  290. #else
  291.         Mshrink((void *)basepage, 512L);
  292. #endif
  293.         r = Pexec(200, (char *)init_prg, init_tail, init_env);
  294.         Pterm((int)r);
  295.     }
  296. }
  297.  
  298.  
  299. /* initialize all interrupt vectors and new trap routines
  300.  * we also get here any TOS variables that we're going to change
  301.  * (e.g. the pointer to the cookie jar) so that rest_intr can
  302.  * restore them.
  303.  */
  304.  
  305. static void
  306. init_intr()
  307. {
  308.     extern long ARGS_ON_STACK mint_bios();
  309.     extern long ARGS_ON_STACK mint_dos();
  310.     extern long ARGS_ON_STACK mint_timer();
  311.     extern long ARGS_ON_STACK mint_vbl();
  312.     extern long ARGS_ON_STACK mint_5ms();
  313.     extern long ARGS_ON_STACK mint_xbios();
  314.     extern long ARGS_ON_STACK reset();
  315.       extern long ARGS_ON_STACK new_ikbd();
  316.       extern long ARGS_ON_STACK new_bus();
  317.       extern long ARGS_ON_STACK new_addr();
  318.       extern long ARGS_ON_STACK new_ill();
  319.       extern long ARGS_ON_STACK new_divzero();
  320.       extern long ARGS_ON_STACK new_trace();
  321.       extern long ARGS_ON_STACK new_priv();
  322.       extern long ARGS_ON_STACK new_linef();
  323.       extern long ARGS_ON_STACK new_chk();
  324.       extern long ARGS_ON_STACK new_trapv();
  325.       extern long ARGS_ON_STACK new_fpcp();
  326.       extern long ARGS_ON_STACK new_mmu();
  327.       extern long ARGS_ON_STACK new_format();
  328.       extern long ARGS_ON_STACK new_cpv();
  329.       extern long ARGS_ON_STACK new_uninit();
  330.       extern long ARGS_ON_STACK new_spurious();
  331.       extern long ARGS_ON_STACK new_pmmuacc();
  332.     short savesr;
  333.     int i;
  334.  
  335.     syskey = (KBDVEC *)Kbdvbase();
  336.     oldkey = *syskey;
  337.  
  338.     xbra_install(&old_ikbd, (long)(&syskey->ikbdsys), new_ikbd);
  339.  
  340. /* gratuitous (void *) for Lattice */
  341.     old_term = (long)Setexc(0x102, (void *)-1UL);
  342.  
  343.     savesr = spl7();
  344.  
  345.     xbra_install(&old_dos, 0x84L, mint_dos);
  346.     save_dos = (long)old_dos.next;
  347.  
  348.     xbra_install(&old_bios, 0xb4L, mint_bios);
  349.     save_bios = (long)old_bios.next;
  350.  
  351.     xbra_install(&old_xbios, 0xb8L, mint_xbios);
  352.     save_xbios = (long)old_xbios.next;
  353.  
  354.     xbra_install(&old_timer, 0x400L, mint_timer);
  355.     xbra_install(&old_criticerr, 0x404L, mint_criticerr);
  356.     xbra_install(&old_5ms, 0x114L, mint_5ms);
  357.     xbra_install(&old_vbl, 4*0x1cL, mint_vbl);
  358.     xbra_install(&old_resvec, 0x42aL, reset);
  359.     old_resval = *((long *)0x426L);
  360.     *((long *)0x426L) = RES_MAGIC;
  361.  
  362.     spl(savesr);
  363.  
  364. #ifdef EXCEPTION_SIGS
  365. /* set up signal handlers */
  366.     xbra_install(&old_bus, 8L, new_bus);
  367.     xbra_install(&old_addr, 12L, new_addr);
  368.     xbra_install(&old_ill, 16L, new_ill);
  369.     xbra_install(&old_divzero, 20L, new_divzero);
  370.     xbra_install(&old_trace, 36L, new_trace);
  371.     xbra_install(&old_priv, 32L, new_priv);
  372.     if (tosvers >= 0x106)
  373.         xbra_install(&old_linef, 44L, new_linef);
  374.     xbra_install(&old_chk, 24L, new_chk);
  375.     xbra_install(&old_trapv, 28L, new_trapv);
  376.     for (i = (int)(sizeof(old_fpcp) / sizeof(old_fpcp[0])); i--; ) {
  377.         xbra_install(&old_fpcp[i], 192L + i * 4, new_fpcp);
  378.     }
  379.     xbra_install(&old_mmuconf, 224L, new_mmu);
  380.     xbra_install(&old_pmmuill, 228L, new_mmu);
  381.     xbra_install(&old_pmmuacc, 232L, new_pmmuacc);
  382.     xbra_install(&old_format, 56L, new_format);
  383.     xbra_install(&old_cpv, 52L, new_cpv);
  384.     xbra_install(&old_uninit, 60L, new_uninit);
  385.     xbra_install(&old_spurious, 96L, new_spurious);
  386. #endif
  387.  
  388. /* set up disk vectors */
  389.     xbra_install(&old_mediach, 0x47eL, new_mediach);
  390.     xbra_install(&old_rwabs, 0x476L, new_rwabs);
  391.     xbra_install(&old_getbpb, 0x472L, new_getbpb);
  392.     olddrvs = *((long *)0x4c2L);
  393.  
  394. /* set up cookie jar */
  395.     oldcookie = *CJAR;    /* CJAR defined in cookie.h */
  396.     install_cookies();
  397. }
  398.  
  399. /* restore all interrupt vectors and trap routines */
  400. /*
  401.  * NOTE: This is *not* the approved way of unlinking XBRA trap handlers.
  402.  * Normally, one should trace through the XBRA chain. However, this is
  403.  * a very unusual situation: when MiNT exits, any TSRs or programs running
  404.  * under MiNT will no longer exist, and so any vectors that they have
  405.  * caught will be pointing to never-never land! So we do something that
  406.  * would normally be considered rude, and restore the vectors to
  407.  * what they were before we ran.
  408.  * BUG: we should restore *all* vectors, not just the ones that MiNT caught.
  409.  */
  410.  
  411. void
  412. restr_intr()
  413. {
  414.     short savesr;
  415.     int i;
  416.  
  417.     savesr = spl7();
  418.     *syskey = oldkey;        /* restore keyboard vectors */
  419.     *tosbp = _base;            /* restore GEMDOS basepage pointer */
  420.     *CJAR = oldcookie;        /* restore old cookie jar */
  421.  
  422. #ifdef EXCEPTION_SIGS
  423.     *((long *)0x08L) = (long) old_bus.next;
  424.     *((long *)0x0cL) = (long) old_addr.next;
  425.     *((long *)0x10L) = (long) old_ill.next;
  426.     *((long *)0x14L) = (long) old_divzero.next;
  427.     *((long *)0x20L) = (long) old_priv.next;
  428.     *((long *)0x24L) = (long) old_trace.next;
  429.     if (old_linef.next)
  430.         *((long *)0x2cL) = (long) old_linef.next;
  431.     *((long *)0x18L) = (long) old_chk.next;
  432.     *((long *)0x1cL) = (long) old_trapv.next;
  433.     for (i = (int)(sizeof(old_fpcp) / sizeof(old_fpcp[0])); i--; ) {
  434.         ((long *)0xc0L)[i] = (long) old_fpcp[i].next;
  435.     }
  436.     *((long *)0xe0L) = (long) old_mmuconf.next;
  437.     *((long *)0xe4L) = (long) old_pmmuill.next;
  438.     *((long *)0xe8L) = (long) old_pmmuacc.next;
  439.     *((long *)0x38L) = (long) old_format.next;
  440.     *((long *)0x34L) = (long) old_cpv.next;
  441.     *((long *)0x3cL) = (long) old_uninit.next;
  442.     *((long *)0x60L) = (long) old_spurious.next;
  443. #endif
  444.     *((long *)0x84L) = (long) old_dos.next;
  445.     *((long *)0xb4L) = (long) old_bios.next;
  446.     *((long *)0xb8L) = (long) old_xbios.next;
  447.     *((long *)0x408L) = old_term;
  448.     *((long *)0x404L) = (long) old_criticerr.next;
  449.     *((long *)0x114L) = (long) old_5ms.next;
  450.     *((long *)0x400L) = (long) old_timer.next;
  451.     *((long *)0x70L) = (long) old_vbl.next;
  452.     *((long *)0x426L) = old_resval;
  453.     *((long *)0x42aL) = (long) old_resvec.next;
  454.     *((long *)0x476L) = (long) old_rwabs.next;
  455.     *((long *)0x47eL) = (long) old_mediach.next;
  456.     *((long *)0x472L) = (long) old_getbpb.next;
  457.     *((long *)0x4c2L) = olddrvs;
  458.  
  459.     spl(savesr);
  460. }
  461.  
  462.  
  463. /* we save the TOS supervisor stack pointer so that we can reset it when
  464.    calling Pterm() (not that anyone will ever want to leave MiNT :-)).
  465.  */
  466.  
  467. long tosssp;        /* TOS supervisor stack pointer */
  468.  
  469.  
  470. /*
  471.  * enter_kernel: called every time we enter the MiNT kernel via a trap
  472.  * call. Sets up the GEMDOS and BIOS vectors to point to TOS, and
  473.  * sets up other vectors and system variables appropriately. Note that
  474.  * calling enter_kernel multiple times is probably NOT a good idea,
  475.  * but the code will allow it.
  476.  * The parameter is a flag telling us whether or not this is a GEMDOS
  477.  * call; the BIOS uses this for checking security of Rwabs.
  478.  */
  479.  
  480. short in_kernel = 0;
  481.  
  482. void ARGS_ON_STACK
  483. enter_kernel(isGEMDOS)
  484.     int isGEMDOS;
  485. {
  486.     short save_sr;
  487.  
  488.     if (in_kernel) return;
  489.  
  490.     save_sr = spl7();
  491.     curproc->in_dos = isGEMDOS;
  492.     save_dos = *((long *) 0x84L);
  493.     save_bios = *((long *) 0xb4L);
  494.     save_xbios = *((long *) 0xb8L);
  495.     *((long *) 0x84L) = (long)old_dos.next;
  496.     *((long *) 0xb4L) = (long)old_bios.next;
  497.     *((long *) 0xb8L) = (long)old_xbios.next;
  498.     *tosbp = _base;
  499.  
  500.     in_kernel = 1;
  501.     spl(save_sr);
  502. }
  503.  
  504. /*
  505.  * leave_kernel: called before leaving the kernel, either back to
  506.  * user mode or when calling a signal handler or the GEMDOS
  507.  * terminate vector. Note that interrupts should be disabled before
  508.  * this routine is called.
  509.  */
  510.  
  511. void ARGS_ON_STACK
  512. leave_kernel()
  513. {
  514.     *((long *) 0x84L) = save_dos;
  515.     *((long *) 0xb4L) = save_bios;
  516.     *((long *) 0xb8L) = save_xbios;
  517.     *tosbp = curproc->base;
  518.     in_kernel = 0;
  519.     curproc->in_dos = 0;
  520. }
  521.  
  522. /*
  523.  * shut down processes; this involves waking them all up, and sending
  524.  * them SIGTERM to give them a chance to clean up after themselves
  525.  */
  526.  
  527. static void
  528. shutmedown(p)
  529.     PROC *p;
  530. {
  531.     UNUSED(p);
  532.     curproc->wait_cond = 0;
  533. }
  534.  
  535. void
  536. shutdown()
  537. {
  538.     PROC *p;
  539.     int proc_left = 0;
  540.  
  541.     curproc->sighandle[SIGCHLD] = SIG_IGN;
  542.  
  543.     for (p = proclist; p; p = p->gl_next) {
  544.         if (p->pid == 0) continue;
  545.         if (p->wait_q != ZOMBIE_Q && p->wait_q != TSR_Q) {
  546.             if (p->wait_q != READY_Q) {
  547.                 short sr = spl7();
  548.                 rm_q(p->wait_q, p);
  549.                 add_q(READY_Q, p);
  550.                 spl(sr);
  551.             }
  552.             post_sig(p, SIGTERM);
  553.             proc_left++;
  554.         }
  555.     }
  556.  
  557.     if (proc_left) {
  558.         /* sleep a little while, to give the other processes a chance to
  559.            shut down
  560.          */
  561.  
  562.         addtimeout(1000, shutmedown);
  563.         do {
  564.             sleep(WAIT_Q, (long)shutdown);
  565.         } while (curproc->wait_cond == (long)shutdown);
  566.     }
  567. }
  568.  
  569. #if defined(__GNUC__) || defined(__MINT__)
  570. int
  571. main(argc, argv, envp)
  572.     int argc;
  573.     char **argv, **envp;
  574. #else
  575. int
  576. main(argc, argv)
  577.     int argc;
  578.     char **argv;
  579. #endif
  580. {
  581.     long *sysbase;
  582.     long r;
  583.     extern int debug_level, debug_logging;    /* in debug.c */
  584.     extern int no_mem_prot;        /* memprot.c */
  585.     extern const char *greet1, *greet2;
  586.                     /* welcome.c */
  587.     static char buf[SPRINTF_MAX];
  588.     static char curpath[128];
  589.     long yn;
  590.     FILEPTR *f;
  591.  
  592. #if defined(__GNUC__) || defined(__MINT__)
  593.     UNUSED(envp);
  594. #endif
  595.  
  596. /* figure out what kind of machine we're running on */
  597. /* biosfs wants to know this; also sets no_mem_prot */
  598. /* 920625 kbad put it here so memprot_warning can be intelligent */
  599.     (void)Supexec(getmch);
  600. #ifdef ONLY030
  601.     if (mcpu != 30) {
  602.         Cconws("\r\nThis version of MiNT requires a 68030.\r\n");
  603.         Cconws("Hit any key to continue.\r\n");
  604.         (void)Cconin();
  605.         Pterm0();
  606.     }
  607. #endif
  608.  
  609. /* Ask the user if s/he wants to boot MiNT */
  610.     if ((Kbshift(-1) & MAGIC_SHIFT) == MAGIC_SHIFT) {
  611.         yn = boot_kernel_p();
  612.         Cconws("\r\n");
  613.         if (!yn)
  614.             Pterm0();
  615.     }
  616.  
  617.     if (argv[0][0] == 0) {    /* maybe started from the desktop */
  618.         curs_off = 1;
  619.     }
  620.  
  621.     yn = 0; /* by default, don't print basepage */
  622.     --argc, ++argv;
  623.     while (argc && **argv == '-') {
  624.         if (argv[0][1] >= '0' && argv[0][1] <= '9') {
  625.         /* a number sets out_device to that device */
  626.             extern int out_device;
  627.             out_device = (int)atol(&argv[0][1]);
  628.         }
  629.         else if (argv[0][1] == 'b') {
  630.         /* print MiNT basepage */
  631.             yn++;
  632.         }
  633.         else if (argv[0][1] == 'd') {
  634.         /* -d increases debugging level */
  635.             debug_level++;
  636.         }
  637.         else if (argv[0][1] == 'm' || argv[0][1] == 'p') {
  638.             int givenotice = (argv[0][2] != 'w');
  639.         /* -m and -p turn off memory protection */
  640.         extern const char *memprot_notice, *memprot_warning;
  641.             if (no_mem_prot) {
  642.                 if (givenotice)
  643.                 Cconws(memprot_notice);
  644.             }
  645.             else {
  646.                 no_mem_prot = 1;
  647.                 if (givenotice)
  648.                 Cconws(memprot_warning);
  649.             }
  650.         }
  651.         else if (argv[0][1] == 'l') {
  652.         /* -l turns on debug logging */
  653.             debug_logging = 1;
  654.         }
  655.         else {
  656.             Cconws("Unknown argument (ignored): ");
  657.             Cconws(*argv);
  658.             Cconws("\r\n");
  659.         }
  660.         ++argv, --argc;
  661.     }
  662.     if (argc) {
  663.         Cconws("Unknown argument ignored: ");
  664.         Cconws(*argv);
  665.         Cconws(" (and all the rest)\r\n");
  666.         }
  667.  
  668. /* greetings */
  669.     Cconws(greet1);
  670.     ksprintf(buf, VERS_STRING, MAJ_VERSION, MIN_VERSION);
  671.     Cconws(buf);
  672.     Cconws(greet2);
  673.  
  674. #ifdef __TURBOC__
  675.     Cconws("PRELIMINARY PureC compiled version!\r\n");
  676. #endif
  677.  
  678.     if (yn)
  679.     {
  680.             ksprintf(buf,"MiNT@%lx\r\nhit a key...",_base);
  681.         Cconws(buf);
  682.         (void)Crawcin();
  683.         Cconws("\r\033K");
  684.     }
  685.  
  686. #ifdef notdef
  687. /* if less than 1 megabyte free, turn off memory protection */
  688.     if (Mxalloc(-1L, 3) < ONE_MEG && !no_mem_prot) {
  689.         extern const char *insuff_mem_warning;
  690.         Cconws(insuff_mem_warning);
  691.         no_mem_prot = 1;
  692.     }
  693. #endif
  694.  
  695. /* look for ourselves as \AUTO\MINTNP.PRG; if so, we turn memory
  696.  * protection off
  697.  */
  698.     if (!no_mem_prot && Fsfirst("\\AUTO\\MINTNP.PRG",0) == 0)
  699.         no_mem_prot = 1;
  700.  
  701. /* check for GEM -- this must be done from user mode */
  702.     gem_active = check_for_gem();
  703.  
  704. /*
  705.  * get the current directory, so that we can switch back to it after
  706.  * the file systems are properly initialized
  707.  */
  708. /* set the current directory for the current process */
  709.     (void)Dgetpath(curpath, 0);
  710.     if (!*curpath) {
  711.         curpath[0] = '\\';
  712.         curpath[1] = 0;
  713.     }
  714.     tosssp = (long)Super(0L);    /* enter supervisor mode */
  715.     if (!no_mem_prot)
  716.         save_mmu();        /* save current MMU setup */
  717.  
  718. /* get GEMDOS pointer to current basepage */
  719. /* 0x4f2 points to the base of the OS; here we can find the OS compilation
  720.    date, and (in newer versions of TOS) where the current basepage pointer
  721.    is kept; in older versions of TOS, it's at 0x602c
  722.  */
  723.     sysbase = *((long **)(0x4f2L));    /* gets the RAM OS header */
  724.     sysbase = (long *)sysbase[2];    /* gets the ROM one */
  725.  
  726.     tosvers = (int)(sysbase[0] & 0x0000ffff);
  727.     if (tosvers == 0x100) {
  728.         if ((sysbase[7] & 0xfffe0000L) == 0x00080000L)
  729.             tosbp = (BASEPAGE **)0x873cL;    /* SPANISH ROM */
  730.         else
  731.             tosbp = (BASEPAGE **) 0x602cL;
  732.         kbshft = (char *) 0x0e1bL;
  733.     } else {
  734.         tosbp = (BASEPAGE **) sysbase[10];
  735.         kbshft = (char *) sysbase[9];
  736.     }
  737.  
  738.     if (tosvers >= 0x0400 && tosvers <= 0x404) {
  739.         bconmap2 = (BCONMAP2_T *)Bconmap(-2);
  740.         if (bconmap2->maptabsize == 1) {
  741.             /* Falcon BIOS Bconmap is busted */
  742.             bconmap2->maptabsize = 3;
  743.         }
  744.         has_bconmap = 1;
  745.     } else {
  746. /* The TT TOS release notes are wrong... this is the real way to test
  747.  * for Bconmap ability
  748.  */
  749.         has_bconmap = (Bconmap(0) == 0);
  750.         if (has_bconmap)
  751.             bconmap2 = (BCONMAP2_T *)Bconmap(-2);
  752.     }
  753.  
  754. /* initialize memory */
  755.     init_mem();
  756.  
  757. /* initialize the basic file systems */
  758.     timestamp = Tgettime();
  759.     datestamp = Tgetdate();
  760.     init_filesys();
  761.  
  762. /* initialize processes */
  763.     init_proc();
  764.  
  765. /* initialize system calls */
  766.     init_dos();
  767.     init_bios();
  768.     init_xbios();
  769.  
  770. /* NOTE: there's a call to kmalloc embedded in install_cookies, which
  771.  * is called by init_intr; so make sure this is the last of the
  772.  * init_* things called!
  773.  */
  774.     init_intr();
  775.     enter_kernel(1);    /* we'll be making GEMDOS calls */
  776.  
  777. #if 0
  778.     if (!gem_active) {
  779. /* make MiNT invisible in the basepage chain, so that
  780.  * programs that rely on a certain basepage chain
  781.  * structure to determine whether or not they were run
  782.  * from the desktop will have a better chance of working.
  783.  * NOTE THAT THIS IS ONLY DONE TO HELP OUT BRAIN-DAMAGED
  784.  * SOFTWARE: do *not* try counting basepages to figure
  785.  * out whether or not you were run from the desktop!!!
  786.  */
  787.         rootproc->base = _base->p_parent;
  788.     } else
  789. #endif
  790.         rootproc->base = _base;
  791.  
  792. /* set up standard file handles for the current process
  793.  * do this here, *after* init_intr has set the Rwabs vector,
  794.  * so that AHDI doesn't get upset by references to drive U:
  795.  */
  796.     f = do_open("U:\\DEV\\CONSOLE", O_RDWR, 0, (XATTR *)0);
  797.     if (!f) {
  798.         FATAL("unable to open CONSOLE device");
  799.     }
  800.     curproc->control = f;
  801.     curproc->handle[0] = f;
  802.     curproc->handle[1] = f;
  803.     f->links = 3;
  804.  
  805.     f = do_open("U:\\DEV\\MODEM1", O_RDWR, 0, (XATTR *)0);
  806.     curproc->aux = f;
  807.     ((struct tty *)f->devinfo)->aux_cnt = 1;
  808.     f->pos = 1;    /* flag for close to --aux_cnt */
  809.     if (has_bconmap) {
  810.     /* If someone has already done a Bconmap call, then
  811.      * MODEM1 may no longer be the default
  812.      */
  813.         bconmap(curbconmap);
  814.         f = curproc->aux;    /* bconmap can change curproc->aux */
  815.     }
  816.     if (f) {
  817.         curproc->handle[2] = f;
  818.         f->links++;
  819.     }
  820.     f = do_open("U:\\DEV\\CENTR", O_RDWR, 0, (XATTR *)0);
  821.     if (f) {
  822.         curproc->handle[3] = curproc->prn = f;
  823.         f->links = 2;
  824.     }
  825.     f = do_open("U:\\DEV\\MIDI", O_RDWR, 0, (XATTR *)0);
  826.     if (f) {
  827.         curproc->midiin = curproc->midiout = f;
  828.         ((struct tty *)f->devinfo)->aux_cnt = 1;
  829.         f->pos = 1;    /* flag for close to --aux_cnt */
  830.         f->links = 2;
  831.     }
  832.  
  833. /* load external file systems */
  834. /* set path first to make sure that MiNT's directory matches
  835.  * GEMDOS's
  836.  */
  837.     d_setpath(curpath);
  838.     
  839.     load_devdriver();
  840.  
  841. #ifndef PROFILING
  842. /* load_filesys causes media changes :-( */
  843.     load_filesys();
  844. #endif
  845.  
  846. /* note that load_filesys changed the
  847.  * directory on us!!
  848.  */
  849.     (void)d_setpath(curpath);
  850.     
  851. /* load the configuration file */
  852.     load_config();
  853.  
  854.     *((long *)0x4c2L) |= PSEUDODRVS;
  855.  
  856.     if (init_env == 0)
  857.         init_env = (char *)_base->p_env;
  858.  
  859. /* empty environment? Set the PATH variable to the root of the current drive */
  860.     if (init_env[0] == 0) {
  861.         static char path_env[] = "PATH=\0C:\0";
  862.         path_env[6] = curproc->curdrv + 'A';
  863.         init_env = path_env;
  864.     }
  865.  
  866. /* if we are MultiTOS, we're running in the AUTO folder, and our INIT is
  867.  * in fact GEM, take the exec_os() vector. (We know that INIT is GEM
  868.  * if the user told us so by using GEM= instead of INIT=.)
  869.  */
  870.     if (!gem_active && init_is_gem) {
  871.         xbra_install(&old_execos, EXEC_OS, (long ARGS_ON_STACK (*)())do_exec_os);
  872.     }
  873.  
  874. /* run any programs appearing after us in the AUTO folder */
  875.     run_auto_prgs();
  876.  
  877. /* run the initial program */
  878. /* if that program is in fact GEM, we start it via exec_os, otherwise
  879.  * we do it with Pexec.
  880.  * the logic is: if the user specified init_prg, and it is not
  881.  * GEM, then we try to execute it; if it *is* GEM (e.g. gem.sys),
  882.  * then we try to execute it if gem is already active, otherwise
  883.  * we jump through the exec_os vector (which we grabbed above) in
  884.  * order to start it. We *never* go through exec_os if we're not in
  885.  * the AUTO folder.
  886.  */
  887.     if (init_prg && (!init_is_gem || gem_active)) {
  888.         r = p_exec(0, (char *)init_prg, init_tail, init_env);
  889.     } else if (!gem_active) {   
  890.         BASEPAGE *bp; int pid;
  891.         bp = (BASEPAGE *)p_exec(7,
  892.           (char *)((long)F_FASTLOAD | F_ALTLOAD | F_ALTALLOC | F_PROT_S),
  893.           (char *)"\0", init_env);
  894.         bp->p_tbase = *((long *) EXEC_OS );
  895. #ifndef MULTITOS
  896.         if (((long *) sysbase[5])[0] == 0x87654321)
  897.           gem_start = ((long *) sysbase[5])[2];
  898.         gem_base = bp;
  899. #endif
  900.         r = p_exec(106, (char *)"GEM", bp, 0L);
  901.         pid = (int)r;
  902.         if (pid > 0) {
  903.             do {
  904.                 r = p_wait3(0, (long *)0);
  905.             } while(pid != ((r & 0xffff0000L) >> 16));
  906.             r &= 0x0000ffff;
  907.         }
  908.     } else {
  909. Cconws("If MiNT is run after GEM starts, you must specify a program\r\n");
  910. Cconws("to run initially in MINT.CNF, with an INIT= line\r\n");
  911.             r = 0;
  912.     }
  913.  
  914.     if (r < 0 && init_prg) {
  915.         ksprintf(buf, "FATAL: couldn't run %s\r\n", init_prg);
  916.         Cconws(buf);
  917.     }
  918.  
  919.     if (r) {
  920.         ksprintf(buf, "exit code: %ld\r\n", r);
  921.         Cconws(buf);
  922.     }
  923.  
  924.     rootproc->base = _base;
  925.  
  926. /* shut down all processes gracefully */
  927.     shutdown();
  928.  
  929. /* put everything back and exit */
  930.     if (!gem_active && init_is_gem) {
  931.     /* we stole exec_os above */
  932.         *((long *)EXEC_OS) = (long)old_execos.next;
  933.     }
  934.     restr_intr();
  935.     close_filesys();
  936.     if (!no_mem_prot)
  937.         restr_mmu();
  938.     restr_screen();
  939.  
  940.     (void)Super((void *)tosssp);    /* gratuitous (void *) for Lattice */
  941.     Cconws("leaving MiNT\r\n");
  942.  
  943.     if (curs_off)
  944.         Cconws("\033f");    /* disable cursor */
  945.  
  946.     return 0;
  947. }
  948.  
  949.  
  950. /*
  951.  * cookie jar handling routines. The "cookie jar" is an area of memory
  952.  * reserved by TOS for TSR's and utility programs; the idea is that
  953.  * you put a cookie in the jar to notify people of available services.
  954.  * The BIOS uses the cookie jar in TOS 1.6 and higher; for earlier versions
  955.  * of TOS, the jar is always empty (unless someone added a cookie before
  956.  * us; POOLFIX does, for example).
  957.  * MiNT establishes an entirely new cookie jar (with the old cookies copied
  958.  * over) and frees it on exit. That's because TSR's run under MiNT
  959.  * will no longer be accessible after MiNT exits.
  960.  * MiNT also puts a cookie in the jar, with tag field 'MiNT' (of course)
  961.  * and with the major version of MiNT in the high byte of the low word,
  962.  * and the minor version in the low byte.
  963.  */
  964.  
  965. void
  966. install_cookies()
  967. {
  968.     COOKIE *cookie;
  969.     int i, ncookies;
  970.     long ncsize;
  971.     extern long rsvf;
  972.  
  973.     /* note that init_intr sets oldcookie to the old cookie jar */
  974.  
  975.     ncookies = 0;
  976.     cookie = oldcookie;
  977.     if (cookie) {
  978.         while (cookie->tag.aslong != 0) {
  979.         /* check for true FPU co-processor */
  980.             if (!strncmp(cookie->tag.aschar, "_FPU",4) &&
  981.                  (cookie->value >> 16) >= 2)
  982.                 fpu = 1;
  983.         /* check for _FLK cookie */
  984.             else if (!strncmp(cookie->tag.aschar, "_FLK",4))
  985.                 flk = 1;
  986.         /* ..and for RSVF */
  987.             else if (!strncmp(cookie->tag.aschar, "RSVF",4))
  988.                 rsvf = cookie->value;
  989.             cookie++; ncookies++;
  990.         }
  991.     }
  992.  
  993.     /*
  994.      * We allocate the cookie jar in global memory so anybody can read
  995.      * it or write it. This code allocates at least 8 more cookies, and
  996.      * then rounds up to a QUANTUM boundary (that's what ROUND does). 
  997.      * Probably, nobody will have to allocate another cookie jar :-)
  998.      */
  999.  
  1000.     /* NOTE: obviously, we can do this only if init_intr is called
  1001.      * _after_ memory, processes, etc. have been initialized
  1002.      */
  1003.     ncsize = (ncookies+8)*sizeof(COOKIE);
  1004.     ncsize = ROUND(ncsize);
  1005.     newcookie = (COOKIE *)alloc_region(core, ncsize, PROT_G);
  1006.  
  1007. /* copy the old cookies to the new jar */
  1008.  
  1009.     for (i = 0, cookie = oldcookie; i < ncookies;) {
  1010. /*
  1011.  * but don't copy RSVF, MiNTs /dev is for real...
  1012.  * (if you want to know whats in there use ls :)
  1013.  */
  1014.         if (!strncmp(cookie->tag.aschar, "RSVF",4)) {
  1015.             ++cookie, --ncookies;
  1016.             continue;
  1017.         }
  1018.         newcookie[i++] = *cookie++;
  1019.     }
  1020.  
  1021. /* install MiNT cookie */
  1022.     strncpy(newcookie[i].tag.aschar, "MiNT", 4);
  1023.     newcookie[i].value = (MAJ_VERSION << 8) | MIN_VERSION;
  1024.     i++;
  1025.  
  1026. /* install _FLK cookie to indicate that file locking works */
  1027.     if (!flk) {
  1028.         strncpy(newcookie[i].tag.aschar, "_FLK", 4);
  1029.         newcookie[i].value = 0;
  1030.         i++;
  1031.     }
  1032.  
  1033. /* jr: install PMMU cookie if memory protection is used */
  1034.     if (!no_mem_prot) {
  1035.         strncpy(newcookie[i].tag.aschar, "PMMU", 4);
  1036.         newcookie[i].value = 0;
  1037.         i++;
  1038.     }
  1039.  
  1040. /* the last cookie should have a 0 tag, and a value indicating the number
  1041.  * of slots, total
  1042.  */
  1043.  
  1044.     newcookie[i].tag.aslong = 0;
  1045.     newcookie[i].value = ncsize/sizeof(COOKIE);
  1046.  
  1047.     *CJAR = newcookie;
  1048.  
  1049. }
  1050.  
  1051. /*
  1052.  * Get the value of the _MCH cookie, if one exists; also set no_mem_prot if
  1053.  * there's a _CPU cookie and you're not on an '030, or if there is none.
  1054.  * This must be done in a separate routine because the machine type and CPU
  1055.  * type are needed when initializing the system, whereas install_cookies is
  1056.  * not called until everything is practically up.
  1057.  * In fact, getmch() should be called before *anything* else is
  1058.  * initialized, so that if we find a MiNT cookie already in the
  1059.  * jar we can bail out early and painlessly.
  1060.  */
  1061.  
  1062. static long
  1063. getmch()
  1064. {
  1065.     COOKIE *jar;
  1066.     int foundcpu = 0;
  1067.     int i;
  1068.     long *sysbase;
  1069.     extern int no_mem_prot;
  1070.  
  1071.     mcpu = 0;
  1072.     jar = *CJAR;    /* CJAR defined in cookie.h */
  1073.     if (jar) {
  1074.         while (jar->tag.aslong != 0) {
  1075.         /* check for machine type */
  1076.             if (!strncmp(jar->tag.aschar, "_MCH",4)) {
  1077.                 mch = jar->value;
  1078.             } else if (!strncmp(jar->tag.aschar, "_CPU",4)) {
  1079.                     /* if not '030 then no memory protection */
  1080.                 mcpu = jar->value;
  1081.                     if (jar->value != 30) no_mem_prot = 1;
  1082.                     foundcpu = 1;
  1083.             } else if (!strncmp(jar->tag.aschar, "_VDO",4)) {
  1084.                 FalconVideo = (jar->value == 0x00030000L);
  1085.                 if (jar->value & 0xffff0000L)
  1086.                     screen_boundary = 15;
  1087.             } else if (!strncmp(jar->tag.aschar, "MiNT",4)) {
  1088.                 Cconws("MiNT is already installed!!\r\n");
  1089.                 Pterm(2);
  1090.             } else if (!strncmp(jar->tag.aschar, "_AKP",4)) {
  1091.                 gl_lang = (int) ((jar->value >> 8) & 0x00ff);
  1092.             } else if (!strncmp(jar->tag.aschar, "PMMU",4)) {
  1093.                 /* jr: if PMMU cookie exists, someone else is
  1094.                    already using the PMMU */
  1095.                 Cconws ("MiNT: PMMU already in use, memory protection turned off.\r\n");
  1096.                 no_mem_prot = 1;
  1097.             }
  1098.             jar++;
  1099.         }
  1100.     }
  1101.     if (!foundcpu) no_mem_prot = 1;
  1102. /*
  1103.  * if no preference found, look at the country code to decide
  1104.  */
  1105.     if (gl_lang < 0) {
  1106.         sysbase = *((long **)(0x4f2L)); /* gets the RAM OS header */
  1107.         sysbase = (long *)sysbase[2];    /* gets the ROM one */
  1108.         i = (int) ((sysbase[7] & 0x7ffe0000L) >> 17L);
  1109.         switch(i) {
  1110.         case 1:        /* Germany */
  1111.         case 8:        /* Swiss German */
  1112.             gl_lang = 1;
  1113.             break;
  1114.         case 2:        /* France */
  1115.         case 7:        /* Swiss French */
  1116.             gl_lang = 2;
  1117.             break;
  1118.         case 4:        /* Spain */
  1119.             gl_lang = 4;
  1120.             break;
  1121.         case 5:        /* Italy */
  1122.             gl_lang = 5;
  1123.             break;
  1124.         default:
  1125.             gl_lang = 0;
  1126.             break;
  1127.         }
  1128.     }
  1129.     
  1130.  
  1131.     if (gl_lang >= MAXLANG || gl_lang < 0)
  1132.         gl_lang = 0;
  1133.     return 0L;
  1134. }
  1135.  
  1136. /*
  1137.  * routines for reading the configuration file
  1138.  * we allow the following commands in the file:
  1139.  * # anything        -- comment
  1140.  * INIT=file        -- specify boot program
  1141.  * CON=file        -- specify initial file/device for handles -1, 0, 1
  1142.  * PRN=file        -- specify initial file for handle 3
  1143.  * BIOSBUF=[yn]        -- if 'n' or 'N' then turn off BIOSBUF feature
  1144.  * DEBUG_LEVEL=n    -- set debug level to (decimal number) n
  1145.  * DEBUG_DEVNO=n    -- set debug device number to (decimal number) n
  1146.  * HARDSCROLL=n        -- set hard-scroll size to n, range 0-99.
  1147.  * SLICES=nnn        -- set multitasking granularity
  1148.  * echo message        -- print a message on the screen
  1149.  * alias drive path    -- make a fake drive pointing at a path
  1150.  * cd dir        -- change directory/drive
  1151.  * exec cmd args    -- execute a program
  1152.  * setenv name val    -- set up environment
  1153.  * sln file1 file2    -- create a symbolic link
  1154.  * ren file1 file2    -- rename a file
  1155.  *
  1156.  * BUG: if you use setenv in mint.cnf, *none* of the original environment
  1157.  * gets passed to children. This is rarely a problem if mint.prg is
  1158.  * in the auto folder.
  1159.  */
  1160.  
  1161. extern short bconbdev, bconbsiz;    /* from bios.c */
  1162.  
  1163. static void
  1164. doset(name, val)
  1165.     char *name, *val;
  1166. {
  1167.     char *t;
  1168.  
  1169.     if (!strcmp(name, "GEM")) {
  1170.         init_is_gem = 1;
  1171.         goto setup_init;
  1172.     } 
  1173.     if (!strcmp(name, "INIT")) {
  1174.         init_is_gem = 0;
  1175. setup_init:
  1176.         if (!*val) return;
  1177.         t = kmalloc(strlen(val)+1);
  1178.         if (!t) return;
  1179.         strcpy(t, val);
  1180.         init_prg = t;
  1181.         while (*t && !isspace(*t)) t++;
  1182. /* get the command tail, too */
  1183.         if (*t) {
  1184.             *t++ = 0;
  1185.             strncpy(init_tail+1, t, 125);
  1186.             init_tail[126] = 0;
  1187.             init_tail[0] = strlen(init_tail+1);
  1188.         }
  1189.         return;
  1190.     }
  1191.     if (!strcmp(name, "CON")) {
  1192.         FILEPTR *f;
  1193.         int i;
  1194.  
  1195.         f = do_open(val, O_RDWR, 0, (XATTR *)0);
  1196.         if (f) {
  1197.             for (i = -1; i < 2; i++) {
  1198.                 do_close(curproc->handle[i]);
  1199.                 curproc->handle[i] = f;
  1200.                 f->links++;
  1201.             }
  1202.             f->links--;    /* correct for overdoing it */
  1203.         }
  1204.         return;
  1205.     }
  1206.     if (!strcmp(name, "PRN")) {
  1207.         FILEPTR *f;
  1208.  
  1209.         f = do_open(val, O_RDWR|O_CREAT|O_TRUNC, 0, (XATTR *)0);
  1210.         if (f) {
  1211.             do_close(curproc->handle[3]);
  1212.             do_close(curproc->prn);
  1213.             curproc->prn = curproc->handle[3] = f;
  1214.             f->links = 2;
  1215.         }
  1216.         return;
  1217.     }
  1218.     if (!strcmp(name, "BIOSBUF")) {
  1219.         if (*val == 'n' || *val == 'N') {
  1220.             if (bconbsiz) bflush();
  1221.             bconbdev = -1;
  1222.         }
  1223.         return;
  1224.     }
  1225.     if (!strcmp(name, "DEBUG_LEVEL")) {
  1226.         extern int debug_level;
  1227.         if (*val >= '0' && *val <= '9')
  1228.             debug_level = (int)atol(val);
  1229.         else ALERT("Bad arg to \"DEBUG_LEVEL\" in cnf file");
  1230.         return;
  1231.     }
  1232.     if (!strcmp(name, "DEBUG_DEVNO")) {
  1233.         extern int out_device;
  1234.         if (*val >= '0' && *val <= '9')
  1235.             out_device= (int)atol(val);
  1236.         else ALERT("Bad arg to \"DEBUG_DEVNO\" in cnf file");
  1237.         return;
  1238.     }
  1239.  
  1240. #ifdef FASTTEXT
  1241.     if (!strcmp(name, "HARDSCROLL")) {
  1242.         int i;
  1243.         extern int hardscroll;
  1244.  
  1245.         if (!strcmp(val, "AUTO")) {
  1246.             hardscroll = -1;
  1247.             return;
  1248.         }
  1249.         i = *val++;
  1250.         if (i < '0' || i > '9') return;
  1251.         hardscroll = i-'0';
  1252.         i = *val;
  1253.         if (i < '0' || i > '9') return;
  1254.         hardscroll = 10*hardscroll + i - '0';
  1255.         return;
  1256.     }
  1257. #endif
  1258.     if (!strcmp(name, "MAXMEM")) {
  1259.         long r;
  1260.  
  1261.         r = atol(val) * 1024L;
  1262.         if (r > 0)
  1263.             p_setlimit(2, r);
  1264.         return;
  1265.     }
  1266.     if (!strcmp(name, "SLICES")) {
  1267.         extern short time_slice;
  1268.  
  1269.         time_slice = atol(val);
  1270.         return;
  1271.     }
  1272.  
  1273.     if (!strcmp(name, "PSEUDODRIVES")) {
  1274.         FORCE("PSEUDODRIVES= no longer supported");
  1275.         return;
  1276.     }
  1277.     FORCE("Unknown variable `%s'", name);
  1278. }
  1279.  
  1280. /* Execute a line from the config file */
  1281. static void
  1282. do_line(line)
  1283.     char *line;
  1284. {
  1285.     char *cmd, *arg1, *arg2;
  1286.     char *newenv;
  1287.     char *t;
  1288.     int i;
  1289.     char delim;
  1290.  
  1291.     while (*line == ' ') line++;    /* skip whitespace at start of line */
  1292.     if (*line == '#') return;    /* ignore comments */
  1293.     if (!*line) return;        /* and also blank lines */
  1294.  
  1295.     cmd = line;
  1296. /* check for variable assignments (e.g. INIT=, etc.) */
  1297. /*
  1298.  * AGK: note we check for spaces whilst scanning so that an environment
  1299.  * variable may include an =, this has the unfortunate side effect that
  1300.  * the '=' _has_ to be concatenated to the variable name (INIT etc.)
  1301.  */
  1302.     for (t = cmd; *t && *t != ' '; t++) {
  1303.         if (*t == '=') {
  1304.             *t++ = 0;
  1305.             doset(cmd, t);
  1306.             return;
  1307.         }
  1308.     }
  1309.  
  1310. /* OK, assume a regular command; break it up into 'cmd', 'arg1', arg2' */
  1311.  
  1312.     while (*line && *line != ' ') line++;
  1313.     delim = ' ';
  1314.     if (*line) {
  1315.         *line++ = 0;
  1316.         while (*line == ' ') line++;
  1317.         if (*line == '"') {
  1318.             delim = '"';
  1319.             line++;
  1320.         }
  1321.     }
  1322.  
  1323.     if (!strcmp(cmd, "echo")) {
  1324.         c_conws(line); c_conws("\r\n");
  1325.         return;
  1326.     }
  1327.     arg1 = line;
  1328.     while (*line && *line != delim) line++;
  1329.     delim = ' ';
  1330.     if (*line) {
  1331.         *line++ = 0;
  1332.         while (*line == ' ') line++;
  1333.         if (*line == '"') {
  1334.             delim = '"';
  1335.             line++;
  1336.         }
  1337.     }
  1338.     if (!strcmp(cmd, "cd")) {
  1339.         int drv;
  1340.         (void)d_setpath(arg1);
  1341.         drv = toupper(*arg1) - 'A';
  1342.         if (arg1[1] == ':') (void)d_setdrv(drv);
  1343.         return;
  1344.     }
  1345.     if (!strcmp(cmd, "exec")) {
  1346.         char cmdline[128];
  1347.         int i;
  1348.  
  1349.         i = strlen(line);
  1350.         if (i > 126) i = 126;
  1351.         cmdline[0] = i;
  1352.         strncpy(cmdline+1, line, i);
  1353.         cmdline[i+1] = 0;
  1354.         i = (int)p_exec(0, arg1, cmdline, init_env);
  1355.         if (i == -33) {
  1356.             FORCE("%s: file not found", arg1);
  1357.         } else if (i < 0) {
  1358.             FORCE("%s: error while attempting to execute", arg1);
  1359.         }
  1360.         return;
  1361.     }
  1362.     if (!strcmp(cmd, "setenv")) {
  1363.         if (strlen(arg1) + strlen(line) + 4 + (env_ptr - init_env) >
  1364.                              env_len) {
  1365.             long j;
  1366.  
  1367.             env_len += 1024;
  1368.             newenv = (char *)m_xalloc(env_len, 0x13);
  1369.             if (init_env) {
  1370.                 t = init_env;
  1371.                 j = env_ptr - init_env;
  1372.                 env_ptr = newenv;
  1373.                 for (i = 0; i < j; i++)
  1374.                     *env_ptr++ = *t++;
  1375.                 if (init_env)
  1376.                     m_free((virtaddr)init_env);
  1377.             } else {
  1378.                 env_ptr = newenv;
  1379.             }
  1380.             init_env = newenv;
  1381.         }
  1382.         while (*arg1) {
  1383.             *env_ptr++ = *arg1++;
  1384.         }
  1385.         *env_ptr++ = '=';
  1386.         while (*line) {
  1387.             *env_ptr++ = *line++;
  1388.         }
  1389.         *env_ptr++ = 0;
  1390.         *env_ptr = 0;
  1391.         return;
  1392.     }
  1393.     if (!strcmp (cmd, "include")) {
  1394.         long fd = f_open (arg1, 0);
  1395.         if (fd < 0) {
  1396.         ALERT ("include: cannot open file %s", arg1);
  1397.         return;
  1398.         }
  1399.         do_file ((int)fd);
  1400.         f_close ((int)fd);
  1401.         return;
  1402.     }
  1403.     arg2 = line;
  1404.     while (*line && *line != delim) line++;
  1405.     if (*line) {
  1406.         *line = 0;
  1407.     }
  1408.     if (!strcmp(cmd, "alias")) {
  1409.         int drv;
  1410.         long r;
  1411.         fcookie root_dir;
  1412.         extern int aliasdrv[];
  1413.  
  1414.         drv = toupper(*arg1) - 'A';
  1415.         if (drv < 0 || drv >= NUM_DRIVES) {
  1416.             ALERT("Bad drive (%c:) in alias", drv+'A');
  1417.             return;
  1418.         }
  1419.         r = path2cookie(arg2, NULL, &root_dir);
  1420.         if (r) {
  1421.             ALERT("alias: TOS error %ld while looking for %s",
  1422.                 r, arg2);
  1423.             return;
  1424.         }
  1425.         aliasdrv[drv] = root_dir.dev + 1;
  1426.         *((long *)0x4c2L) |= (1L << drv);
  1427.         release_cookie(&curproc->curdir[drv]);
  1428.         dup_cookie(&curproc->curdir[drv], &root_dir);
  1429.         release_cookie(&curproc->root[drv]);
  1430.         curproc->root[drv] = root_dir;
  1431.         return;
  1432.     }
  1433.     if (!strcmp(cmd, "sln")) {
  1434.         (void)f_symlink(arg1, arg2);
  1435.         return;
  1436.     }
  1437.     if (!strcmp(cmd, "ren")) {
  1438.         (void)f_rename(0, arg1, arg2);
  1439.         return;
  1440.     }
  1441.     FORCE("syntax error in mint.cnf near: %s", cmd);
  1442. }
  1443.  
  1444. #undef BUF
  1445. #undef LINE
  1446.  
  1447. #define BUF 512
  1448. #define LINE 256
  1449.  
  1450. static void
  1451. do_file(fd)
  1452.     int fd;
  1453. {
  1454.     long r;
  1455.     char buf[BUF+1], c;
  1456.     char line[LINE+1];
  1457.     char *from;
  1458.     int count = 0;
  1459.  
  1460.      buf[BUF] = 0;
  1461.     from = &buf[BUF];
  1462.     line[LINE] = 0;
  1463.  
  1464.     for(;;) {
  1465.         c = *from++;
  1466.         if (!c) {
  1467.             r = f_read(fd, (long)BUF, buf);
  1468.             if (r <= 0) break;
  1469.             buf[r] = 0;
  1470.             from = buf;
  1471.         } else if (c == '\r') {
  1472.             continue;
  1473.         } else if (c == '\n') {
  1474.             line[count] = 0;
  1475.             do_line(line);
  1476.             count = 0;
  1477.         } else {
  1478.             if (count < LINE) {
  1479.                 line[count++] = c;
  1480.             }
  1481.         }
  1482.     }
  1483.     if (count) {
  1484.         line[count] = 0;
  1485.         do_line(line);
  1486.     }
  1487. }
  1488.  
  1489. void
  1490. load_config()
  1491. {
  1492.     int fd;
  1493.  
  1494.     fd = (int) f_open("mint.cnf", 0);
  1495.     if (fd < 0)
  1496.         fd = (int) f_open("\\mint\\mint.cnf", 0);
  1497.     if (fd < 0)
  1498.         fd = (int) f_open("\\multitos\\mint.cnf", 0);
  1499.     if (fd < 0) return;
  1500.     do_file(fd);
  1501.     f_close(fd);
  1502. }
  1503.  
  1504. /*
  1505.  * run programs in the AUTO folder that appear after MINT.PRG
  1506.  * some things to watch out for:
  1507.  * (1) make sure GEM isn't active
  1508.  * (2) make sure there really is a MINT.PRG in the auto folder
  1509.  */
  1510.  
  1511. /*
  1512.  * some global variables used to see if GEM is active
  1513.  */
  1514. static short aes_intout[64];
  1515. static short aes_dummy[64];
  1516. static short aes_globl[15];
  1517. static short aes_cntrl[6] = { 10, 0, 1, 0, 0 };
  1518.  
  1519. short *aes_pb[6] = { aes_cntrl, aes_globl, aes_dummy, aes_intout,
  1520.              aes_dummy, aes_dummy };
  1521.  
  1522. /* check for whether GEM is active; remember, this *must* be done in
  1523.  * user mode
  1524.  */
  1525.  
  1526. static int
  1527. check_for_gem()
  1528. {
  1529.     call_aes(aes_pb);    /* does an appl_init */
  1530.     return aes_globl[0];
  1531. }
  1532.  
  1533. static void
  1534. run_auto_prgs()
  1535. {
  1536.     DTABUF *dta;
  1537.     long r;
  1538.     static char pathspec[32] = "\\AUTO\\";
  1539.     short runthem = 0;    /* set to 1 after we find MINT.PRG */
  1540.  
  1541. /* if the AES is running, don't check AUTO */
  1542.  
  1543.     if (gem_active) {
  1544.         return;
  1545.     }
  1546.  
  1547. /* OK, now let's run through \\AUTO looking for
  1548.  * programs...
  1549.  */
  1550.     dta = (DTABUF *)f_getdta();
  1551.     r = f_sfirst("\\AUTO\\*.PRG", 0);
  1552.     while (r >= 0) {
  1553.         if (!strcmp(dta->dta_name, "MINT.PRG") ||
  1554.             !strcmp(dta->dta_name, "MINTNP.PRG"))
  1555.             runthem = 1;
  1556.         else if (runthem) {
  1557.             strcpy(pathspec+6, dta->dta_name);
  1558.             (void)p_exec(0, pathspec, (char *)"", init_env);
  1559.         }
  1560.         r = f_snext();
  1561.     }
  1562. }
  1563.